/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package session.TX;

import entity.tta.DataModel;
import entity.OutletReservation;
import entity.PurchasedItem;
import entity.PurchasedItem_Regular;
import entity.Users;
import java.util.Calendar;
import java.util.List;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

/**
 *
 * @author Chen Zhe
 */
@Stateless
public class OutletDataModelSB {

    @PersistenceContext
    private EntityManager em;

    public OutletDataModelSB() {
    }

    public void updateDataModel(Long outletId) {

        Calendar fromTime = Calendar.getInstance();
        String[] countries;
        String[] ageGroups;

        Query q1 = em.createQuery("SELECT c FROM DataModel c WHERE c.outlet_id = :outletId");
        q1.setParameter("outletId", outletId);
        List<DataModel> dataModels = q1.getResultList();

        if (dataModels.isEmpty()) {
            //if select from DataModel, there is no DataModel existed for outletId, should create data model first
            DataModel dataModel = new DataModel();
            Long[][] cluster = dataModel.getCluster();
            fromTime = dataModel.getTime_stamp();
            countries = dataModel.getCountriesArray();
            ageGroups = dataModel.getAgeGroupsArray();
            
            //updatacluster(outletId) used in DMS
            cluster = updateCluster(cluster, outletId, fromTime, countries, ageGroups);
            dataModel.setCluster(cluster);
            
            //updateMonthSale(outletId, fromTime, countries, ageGroups) used in PIP page
            
            //updateMonthReservation(outletId, fromTime, countries, ageGroups) used in PIP page
            
            //updateMonthSurvey(outletId, fromTime, countries, ageGroups) used in PIP page
            
            //updateSaleAgeGroup(outletId, fromTime, countries, ageGroups) used in DMS page
            
            //updateSaleCountry(outletId, fromTime, countries, ageGroups) used in DMS page
            
            //updateReservationAgeGroup(outletId, fromTime, countries, ageGroups) used in DMS page
            
            //updateReservationCountry(outletId, fromTime, countries, ageGroups) used in DMS page
            
            //updateDishSale(outletId, fromTime, countries, ageGroups) used in DMS page
            
            //updateLoyalCustomerList(outletId, countries, ageGroups) used in DMS page
            
            em.persist(dataModel);
        } else {
            //if already have DataModel, just update to the the system time stemp right now
            DataModel dataModel = dataModels.get(0);
            Long[][] cluster = dataModel.getCluster();
            fromTime = dataModel.getTime_stamp();
            countries=dataModel.getCountriesArray();
            ageGroups= dataModel.getAgeGroupsArray();
            
            //update cluster
            cluster = updateCluster(cluster, outletId, fromTime, countries, ageGroups);
            dataModel.setCluster(cluster);
            //updateMonthSale(outletId, fromTime, countries, ageGroups) used in PIP page
            
            //updateMonthReservation(outletId, fromTime, countries, ageGroups) used in PIP page
            
            //updateMonthSurvey(outletId, fromTime, countries, ageGroups) used in PIP page
            
            //updateSaleAgeGroup(outletId, fromTime, countries, ageGroups) used in DMS page
            
            //updateSaleCountry(outletId, fromTime, countries, ageGroups) used in DMS page
            
            //updateReservationAgeGroup(outletId, fromTime, countries, ageGroups) used in DMS page
            
            //updateReservationCountry(outletId, fromTime, countries, ageGroups) used in DMS page
            
            //updateDishSale(outletId, fromTime, countries, ageGroups) used in DMS page
            
            //updateLoyalCustomerList(outletId, countries, ageGroups) used in DMS page
            em.persist(dataModel);
        }
    }

    // update cluster to the current system time  updateCluster: STEP1
    private Long[][] updateCluster(Long[][] cluster, Long outletId, Calendar fromTime, String[] countries, String[] ageGroups) {

        //go through the List<PurchasedItem> from fromTime
        List<PurchasedItem_Regular> transactionDatas = getOutletTransactions(outletId, fromTime);
        for (Object o : transactionDatas) {
            PurchasedItem_Regular p = (PurchasedItem_Regular) o;
            //get the country and agrGroup of this PurchasedItem
            String country = p.getBuyer_country();
            Integer age = p.getBuyer_age();
            String ageGroup = getAgeGroup(ageGroups, age);

            //Add one to the corrsponding 2dArray(cluster)  
            int x = getIndex(countries, country);
            int y = getIndex(ageGroups, ageGroup);
            cluster[x][y]++;
        }

        //go through the List<OutletReservation> from fromTime
        List<OutletReservation> outletReservations = getOutletReservations(outletId);
        for (Object o : outletReservations) {
            // get customer's country and ageGroup
            OutletReservation r = (OutletReservation) o;
            Users customer = r.getCustomer();
            String customerEmail = customer.getEmail();
            String country = customer.getCountry().getCountry();
            Calendar birthDay = Calendar.getInstance();
            birthDay.setTime(customer.getBirthDate());
            Calendar currentTime = Calendar.getInstance();
            Integer age = new Integer(currentTime.get(Calendar.YEAR) - birthDay.get(Calendar.YEAR));
            String ageGroup = getAgeGroup(ageGroups, age);
            //add one to the corrsponding 2dArray(cluster)
            int x = getIndex(countries, country);
            int y = getIndex(ageGroups, ageGroup);
            cluster[x][y]++;
        }

        return cluster;
    }

    // get the times of transactions take place at an outlet updateCluster: STEP2
    private List<PurchasedItem_Regular> getOutletTransactions(Long outletId, Calendar fromTime) {
        Query q1 = em.createQuery("SELECT c FROM PurchasedItem_Regular c WHERE c.outlet_id = :outletId AND "
                + "c.time_stamp>:fromTime ORDER BY c.outlet_id, c.time_stamp");
        q1.setParameter("outletId", outletId);
        q1.setParameter("fromTime", fromTime);
        List<PurchasedItem_Regular> transactionDatas = getTransactionData(q1.getResultList());
        return transactionDatas;
    }
    
    //get the representative purchsed items(Transact Data), one transaction will be represented by a single purchased item  updateCluster:step3
    private List<PurchasedItem_Regular> getTransactionData(List<PurchasedItem_Regular> purchasedItems) {
        List<PurchasedItem_Regular> transactionDatas = purchasedItems;
        Calendar tempTimeStamp = Calendar.getInstance();
        //Have to initialize the tempTimeStamp, When run it the first time, set year to 1000 will get all the purchased item records 
        tempTimeStamp.set(Calendar.YEAR, 1000);
        String tempCustomerEmail = "";
        for (Object o : transactionDatas) {
            PurchasedItem p = (PurchasedItem) o;
            if (p.getCustomerEmail().equals(tempCustomerEmail) && p.getTime_stamp().equals(tempTimeStamp)) {
                transactionDatas.remove(p);
            }
            tempTimeStamp = p.getTime_stamp();
            tempCustomerEmail = p.getCustomerEmail();
        }
        return transactionDatas;
    }

    //get the times of table bookings take place at an outlet
    private List<OutletReservation> getOutletReservations(Long outletId) {
        Query q1 = em.createQuery("SELECT c FROM OutletReservation c WHERE c.outlet_id = :outletId AND confirmStatus =:confirmStatus");
        q1.setParameter("outletId", outletId);
        q1.setParameter("confirmStatus", true);

        return (List<OutletReservation>) q1.getResultList();
    }


    private int getIndex(String[] array, String word) {
        for (int i = 0; i < array.length; i++) {
            if (array[i].equals(word)) {
                return i;
            }
        }
        return 0;
    }

    private String getAgeGroup(String[] ageGroups, Integer age) {
        for (int i = 0; i < ageGroups.length; i++) {
            String[] ageBoundaries = ageGroups[i].split("-");
            Integer minAge = new Integer(ageBoundaries[0]);
            Integer maxAge = new Integer(ageBoundaries[1]);
            if (minAge <= age && age < maxAge) {
                return ageGroups[i];
            }
        }
        return "ProblemOccurInGettingAgeGroup";

    }
}
